package org.dromara.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.app.domain.AppOperLog;
import org.dromara.app.domain.bo.AppOperLogBo;
import org.dromara.app.domain.vo.AppOperLogVo;
import org.dromara.app.mapper.AppOperLogMapper;
import org.dromara.app.service.AppOperLogService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * App端操作日志Service业务层处理
 *
 * @author ruoyi
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AppOperLogServiceImpl extends ServiceImpl<AppOperLogMapper, AppOperLog> implements AppOperLogService {

    private final AppOperLogMapper baseMapper;

    /**
     * 查询App端操作日志
     */
    @Override
    public AppOperLogVo queryById(Long operId) {
        return baseMapper.selectVoById(operId);
    }

    /**
     * 查询App端操作日志列表
     */
    @Override
    public TableDataInfo<AppOperLogVo> queryPageList(AppOperLogBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<AppOperLog> lqw = buildQueryWrapper(bo);
        Page<AppOperLogVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询App端操作日志列表
     */
    @Override
    public List<AppOperLogVo> queryList(AppOperLogBo bo) {
        LambdaQueryWrapper<AppOperLog> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<AppOperLog> buildQueryWrapper(AppOperLogBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTitle()), AppOperLog::getTitle, bo.getTitle());
        lqw.eq(bo.getBusinessType() != null, AppOperLog::getBusinessType, bo.getBusinessType());
        lqw.like(StringUtils.isNotBlank(bo.getMethod()), AppOperLog::getMethod, bo.getMethod());
        lqw.eq(StringUtils.isNotBlank(bo.getRequestMethod()), AppOperLog::getRequestMethod, bo.getRequestMethod());
        lqw.like(StringUtils.isNotBlank(bo.getOperName()), AppOperLog::getOperName, bo.getOperName());
        lqw.like(StringUtils.isNotBlank(bo.getOperIp()), AppOperLog::getOperIp, bo.getOperIp());
        lqw.eq(bo.getStatus() != null, AppOperLog::getStatus, bo.getStatus());
        lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
            AppOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
        lqw.orderByDesc(AppOperLog::getOperTime);
        return lqw;
    }

    /**
     * 新增App端操作日志
     */
    @Override
    public Boolean insertByBo(AppOperLogBo bo) {
        AppOperLog add = MapstructUtils.convert(bo, AppOperLog.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setOperId(add.getOperId());
        }
        return flag;
    }

    /**
     * 修改App端操作日志
     */
    @Override
    public Boolean updateByBo(AppOperLogBo bo) {
        AppOperLog update = MapstructUtils.convert(bo, AppOperLog.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(AppOperLog entity) {
        // TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除App端操作日志
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 记录操作日志
     */
    @Override
    public void recordOperLog(String title, Integer businessType, String method, String requestMethod,
                             String operName, String operUrl, String operIp, String operLocation,
                             String operParam, String jsonResult, Integer status, String errorMsg, Long costTime) {
        AppOperLog operLog = new AppOperLog();
        operLog.setTitle(title);
        operLog.setBusinessType(businessType);
        operLog.setMethod(method);
        operLog.setRequestMethod(requestMethod);
        operLog.setOperName(operName);
        operLog.setOperUrl(operUrl);
        operLog.setOperIp(operIp);
        operLog.setOperLocation(operLocation);
        operLog.setOperParam(operParam);
        operLog.setJsonResult(jsonResult);
        operLog.setStatus(status);
        operLog.setErrorMsg(errorMsg);
        operLog.setOperTime(LocalDateTime.now());
        operLog.setCostTime(costTime);
        
        try {
            baseMapper.insert(operLog);
        } catch (Exception e) {
            log.error("记录操作日志失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 根据操作人查询操作日志
     */
    @Override
    public List<AppOperLogVo> queryByOperName(String operName) {
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(operName), AppOperLog::getOperName, operName);
        lqw.orderByDesc(AppOperLog::getOperTime);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 清空操作日志
     */
    @Override
    public void cleanOperLog() {
        baseMapper.delete(Wrappers.lambdaQuery());
    }

    /**
     * 根据时间范围删除操作日志
     */
    @Override
    public void deleteOperLogByTime(LocalDateTime beginTime, LocalDateTime endTime) {
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        if (beginTime != null) {
            lqw.ge(AppOperLog::getOperTime, beginTime);
        }
        if (endTime != null) {
            lqw.le(AppOperLog::getOperTime, endTime);
        }
        baseMapper.delete(lqw);
    }

    /**
     * 获取操作统计信息
     */
    @Override
    public Long getOperLogCount(String operName, LocalDateTime beginTime, LocalDateTime endTime) {
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(operName), AppOperLog::getOperName, operName);
        if (beginTime != null) {
            lqw.ge(AppOperLog::getOperTime, beginTime);
        }
        if (endTime != null) {
            lqw.le(AppOperLog::getOperTime, endTime);
        }
        return baseMapper.selectCount(lqw);
    }

    /**
     * 获取用户行为分析数据
     */
    @Override
    public List<AppOperLogVo> getUserBehaviorAnalysis(String operName, Integer days) {
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(operName), AppOperLog::getOperName, operName);
        if (days != null && days > 0) {
            LocalDateTime startTime = LocalDateTime.now().minusDays(days);
            lqw.ge(AppOperLog::getOperTime, startTime);
        }
        lqw.orderByDesc(AppOperLog::getOperTime);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 获取热门操作统计
     */
    @Override
    public List<AppOperLogVo> getPopularOperations(Integer days, Integer limit) {
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        if (days != null && days > 0) {
            LocalDateTime startTime = LocalDateTime.now().minusDays(days);
            lqw.ge(AppOperLog::getOperTime, startTime);
        }
        lqw.eq(AppOperLog::getStatus, 0); // 只统计成功的操作
        lqw.orderByDesc(AppOperLog::getOperTime);
        
        List<AppOperLogVo> allLogs = baseMapper.selectVoList(lqw);
        
        // 按操作标题分组统计
        Map<String, Long> operationCount = allLogs.stream()
            .collect(Collectors.groupingBy(AppOperLogVo::getTitle, Collectors.counting()));
        
        // 返回前N个热门操作
        return allLogs.stream()
            .collect(Collectors.groupingBy(AppOperLogVo::getTitle))
            .entrySet().stream()
            .sorted((e1, e2) -> Long.compare(e2.getValue().size(), e1.getValue().size()))
            .limit(limit != null ? limit : 10)
            .flatMap(entry -> entry.getValue().stream().limit(1))
            .collect(Collectors.toList());
    }

    /**
     * 获取错误操作统计
     */
    @Override
    public List<AppOperLogVo> getErrorOperations(Integer days) {
        LambdaQueryWrapper<AppOperLog> lqw = Wrappers.lambdaQuery();
        if (days != null && days > 0) {
            LocalDateTime startTime = LocalDateTime.now().minusDays(days);
            lqw.ge(AppOperLog::getOperTime, startTime);
        }
        lqw.eq(AppOperLog::getStatus, 1); // 只查询异常操作
        lqw.orderByDesc(AppOperLog::getOperTime);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 批量记录操作日志
     */
    @Override
    public void batchInsertOperLog(List<AppOperLogBo> operLogs) {
        if (operLogs == null || operLogs.isEmpty()) {
            return;
        }
        
        List<AppOperLog> logs = operLogs.stream()
            .map(bo -> MapstructUtils.convert(bo, AppOperLog.class))
            .collect(Collectors.toList());
        
        try {
            this.saveBatch(logs);
        } catch (Exception e) {
            log.error("批量记录操作日志失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 异步记录操作日志
     */
    @Async
    @Override
    public void asyncRecordOperLog(AppOperLogBo bo) {
        try {
            insertByBo(bo);
        } catch (Exception e) {
            log.error("异步记录操作日志失败: {}", e.getMessage(), e);
        }
    }

}